<template>
  <view
    ref="bodywk"
    @click="hanlder"
    :class="[customClass, 'overflow']"
    :style="[computedHeight ? { height: computedHeight } : '', computedWidth ? { width: computedWidth } : '', customCSSStyle]"
  >
    <!-- #ifdef APP-NVUE -->
    <view v-if="isLoadEl" ref="nvueElAni" :animation="animationData" :class="['flex-col flex ', animationName + reverseAniPrefxname, customClass]">
      <slot name="default"></slot>
    </view>
    <!-- #endif -->
    <!-- #ifndef APP-NVUE -->
    <view
      v-if="isLoadEl"
      ref="nvueElAni"
      :style="{
        transitionDuration: `${durationtos}ms`,
        transitionTimingFunction: 'ease',
      }"
      :class="['flex-col flex ', animationClassName, customClass]"
    >
      <slot name="default"></slot>
    </view>
    <!-- #endif -->
  </view>
</template>

<script lang="ts" setup>
/**
 * 动画
 * @description 提供了6组动画，并且每组件动画都支持反转播放，相当于12组动画了。可用于任何元素，进入场和出场的动画。
 */
import { getCurrentInstance, computed, ref, provide, inject, onMounted, onUnmounted, nextTick, watch } from 'vue';
import { cssstyle } from '@/tool/lib/interface';
import { custom_props, computedClass, computedStyle } from '@/tool/lib/minxs';
// #ifdef APP-PLUS-NVUE
const Binding = uni.requireNativePlugin('bindingx');
const dom = uni.requireNativePlugin('dom');
const animation = uni.requireNativePlugin('animation');
// #endif
// 混淆props共有参数
const props = defineProps({
  ...custom_props,
  duration: {
    type: Number,
    default: 300,
  },
  delay: {
    type: Number,
    default: 0,
  },
  //动画名称
  name: {
    type: String,
    default: 'fade', //fade,left,right,up,down,zoom
  },
  autoPlay: {
    type: Boolean,
    default: true,
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  height: {
    type: [Number, String],
    default: 0,
  },
  width: {
    type: [Number, String],
    default: 0,
  },
  //是否反向动画
  reverse: {
    type: [Boolean, String],
    default: false,
  },
  //每变动一次，就重置动画一下，这个属性不对外，特殊情况使用。
  initByWechat: {
    type: Boolean,
    default: false,
  },
});
const emits = defineEmits(['start', 'end', 'click']);

function hanlder(e: any) {
  emits('click', e);
}
const proxy = getCurrentInstance()?.proxy ?? null;
//自定义样式：
const customCSSStyle = computed(() => computedStyle(props));
//自定类
const customClass = computed(() => computedClass(props));
//高度，
const computedHeight = computed(() => {
  if (!props.height || !Number(props.height)) {
    return 0;
  }
  if (String(props.height).indexOf('px') > -1 || String(props.height).indexOf('rpx') > -1) {
    return String(props.height);
  }
  return String(props.height) + 'rpx';
});

// 宽度
const computedWidth = computed(() => {
  if (!props.width) {
    return 0;
  }
  if (String(props.width).indexOf('px') > -1 || String(props.width).indexOf('rpx') > -1) {
    return props.width;
  }
  return props.width + 'rpx';
});
//动画名称
const animationName = computed(() => props.name || 'fade');
//动画时长
const durationtos = ref(props.duration);
//是否反转。
const computedReverse = computed(() => props.reverse);
//反转动画前缀
const reverseAniPrefxname = computed(() => (computedReverse.value ? '-reverse' : ''));
//非nvue
const animationClassName = ref(animationName.value + reverseAniPrefxname.value);
//动画播放状态。0未开始,结束播放，1开始播放中,2结束。
const animationStatus = ref(0);
const zhid = ref<any>(Number(uni.$tm.u.getUid(3)));
//是否渲染完成。
const isLoadEl = ref(false);
//css3动画数据。
const animationData = ref(null);
watch([() => props.initByWechat, () => props.name], () => {
  reset();
});
watch([() => props.name], () => {
  animationClassName.value = animationName.value + reverseAniPrefxname.value;
});
function init() {
  nextTick(() => {
    isLoadEl.value = true;
    if (props.autoPlay == true && !props.disabled) {
      nextTick(() => play());
    }
  });
}

function play() {
  if (props.disabled == true) return;
  animationStatus.value = 0;
  // #ifdef APP-NVUE
  clearTimeout(zhid.value);
  nextTick(function () {
    zhid.value = setTimeout(function () {
      emits('start');
      nvueAmatons();
    }, 50);
  });
  // #endif
  // #ifndef APP-NVUE
  noNvueAmations();
  // #endif
}

function stop() {
  if (props.disabled == true) return;
  clearTimeout(zhid.value);
  animationStatus.value = 0;
}

function reset() {
  stop();
  animationStatus.value = 0;
}
//对外暴露方法。
defineExpose({
  init: init,
  play: play,
  stop: stop,
  reset: reset,
});
//获取当前播放状态。
function getPlayStatus() {
  return animationStatus.value;
}

onMounted(() => init());
onUnmounted(() => {
  clearTimeout(zhid.value);
  animationStatus.value = 0;
});
function nvueAmatonsReset() {
  var el = proxy?.$refs.nvueElAni;
  let propsAni = {};
  let rs = !computedReverse.value;
  return new Promise((su) => {
    if (animationName.value == 'fade') {
      propsAni = {
        opacity: rs ? 0 : 1,
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'up') {
      propsAni = {
        opacity: 1,
        transform: rs ? 'translateY(0%)' : 'translateY(-100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'down') {
      propsAni = {
        opacity: 1,
        transform: rs ? 'translateY(0%)' : 'translateY(100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'right') {
      propsAni = {
        opacity: 1,
        transform: rs ? 'translateX(0%)' : 'translateX(100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'left') {
      propsAni = {
        opacity: 1,
        transform: rs ? 'translateX(0%)' : 'translateX(-100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'zoom') {
      propsAni = {
        opacity: rs ? 0 : 1,
        transform: rs ? 'scale(0.7,0.7)' : 'scale(1,1)',
        transformOrigin: 'center center',
      };
    }
    animation.transition(
      el,
      {
        styles: propsAni,
        duration: 1, //ms
        timingFunction: 'ease',
        delay: 0, //ms
      },
      () => {
        su(true);
      }
    );
  });
}
function nvueAmatons() {
  var el = proxy?.$refs.nvueElAni;
  let propsAni = {};
  nvueAmatonsReset().then(() => {
    if (animationName.value == 'fade') {
      propsAni = {
        opacity: computedReverse.value ? 0 : 1,
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'up') {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? 'translateY(0%)' : 'translateY(-100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'down') {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? 'translateY(0%)' : 'translateY(100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'right') {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? 'translateX(0%)' : 'translateX(100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'left') {
      propsAni = {
        opacity: 1,
        transform: computedReverse.value ? 'translateX(0%)' : 'translateX(-100%)',
        transformOrigin: 'center center',
      };
    } else if (animationName.value == 'zoom') {
      propsAni = {
        opacity: computedReverse.value ? 0 : 1,
        transform: computedReverse.value ? 'scale(0.7,0.7)' : 'scale(1,1)',
        transformOrigin: 'center center',
      };
    }
    emits('start');
    animationStatus.value = 1;
    clearTimeout(zhid.value);
    zhid.value = setTimeout(function () {
      animation.transition(
        el,
        {
          styles: propsAni,
          duration: props.duration, //ms
          timingFunction: 'ease',
          delay: 0, //ms
        },
        () => {
          emits('end');
          animationStatus.value = 2;
        }
      );
    }, 20);
  });
}

function noNvueAmations() {
  clearTimeout(zhid.value);
  zhid.value = setTimeout(() => {
    if (computedReverse.value) {
      animationClassName.value = animationName.value;
    } else {
      animationClassName.value = animationName.value + '-reverse';
    }
    zhid.value = setTimeout(() => {
      emits('end');
    }, props.duration);
  }, 20);
}
</script>

<style scoped>
.fade {
  opacity: 0;
}

.fade-reverse {
  opacity: 1;
}

.up {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  position: absolute;
  top: 0%;
  /* #endif */
}

.up-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(-101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  position: absolute;
  top: -100%;
  /* #endif */
}

.down {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  position: absolute;
  bottom: 0%;
  /* #endif */
}

.down-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateY(101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  position: absolute;
  bottom: -100%;
  /* #endif */
}

.left {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  left: 0%;
  position: absolute;
  /* #endif */
}

.left-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(-101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  left: -101%;
  position: absolute;
  /* #endif */
}

.right {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(0%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  right: 0%;
  position: absolute;
  /* #endif */
}

.right-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: translateX(101%);
  /* #endif */
  /* #ifndef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  right: -101%;
  position: absolute;
  /* #endif */
}

.zoom {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: scale(0.7, 0.7);
  /* #endif */
  opacity: 0;
}

.zoom-reverse {
  /* #ifdef APP-NVUE || MP-WEIXIN || MP-ALIPAY || H5 */
  transform: scale(1, 1);
  /* #endif */
  opacity: 1;
}
</style>
